package com.jielihaofeng.nettyadvance.protocol;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageCodec;
import lombok.extern.slf4j.Slf4j;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.List;

/**
 * @author Johnnie Wind
 * @description 自定义消息编解码器
 * @date 2021/11/16 16:48
 */
@Slf4j
@ChannelHandler.Sharable
/**
 * 必须和 LengthFieldBasedFrameDecoder 一起使用，确保接到的 ByteBuf 消息是完整的
 */
public class MessageCodec extends ByteToMessageCodec<Message> {

    @Override
    protected void encode(ChannelHandlerContext ctx, Message msg, ByteBuf out) throws Exception {
        // 4个字节的魔数
        out.writeBytes(new byte[]{1, 2, 3, 4});
        // 1个字节的版本
        out.writeByte(1);
        // 1个字节序列化方式 jdk 0 ，json 1
        out.writeByte(0);
        // 1个字节的指令类型
        out.writeByte(msg.getMessageType());
        // 4个字节的请求序号
        out.writeInt(msg.getSequenceId());
        // 无意义，对齐填充
        out.writeByte(0xff);
        // 获取内容的字节数组（jdk序列化方式）
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(msg);
        byte[] bytes = bos.toByteArray();
        // 4个字节的长度
        out.writeInt(bytes.length);
        // 写入内容
        out.writeBytes(bytes);
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        // 读4个字节 魔数
        int magicNum = in.readInt();
        // 读1个字节 版本
        byte version = in.readByte();
        // 读1个字节 序列化方式
        byte serializerType = in.readByte();
        // 读1个字节 指令类型
        byte messageType = in.readByte();
        // 读1个字节 请求序号
        int sequenceId = in.readInt();
        // 读1个字节 对齐填充
        in.readByte();
        // 读4个字节 消息长度
        int length = in.readInt();
        // 读消息内容
        byte[] bytes = new byte[length];
        in.readBytes(bytes, 0, length);
        // 反序列化得到消息内容对象
        // jdk方式
        if (serializerType == 0) {
            ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
            ObjectInputStream ois = new ObjectInputStream(bis);
            Message message = (Message) ois.readObject();
            log.debug("{}, {}, {}, {}, {}, {}", magicNum, version, serializerType, messageType, sequenceId, length);
            log.debug("{}", message);
            // 解析出来的消息存入list，给下一个handler使用
            out.add(message);
        }
    }
}
